package com.yunhe.history.domain.data;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.google.common.collect.Lists;
import com.yunhe.common.util.CollectionUtil;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.TreeMap;

public class ChargeAndDischargeCurve {

    private String date;

    @JsonIgnore
    private List<TreeMap<Date,Double>> chargeCurve;

    @JsonIgnore
    private List<TreeMap<Date,Double>> disChargeCurve;

    @JsonIgnore
    private List<TreeMap<Date,Double>> unkwonMeasMaps;

    private Double chargeIntegral = 0d;

    private Double dischargeIntegral = 0d;

    private Double unkownIntegral = 0d;


    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

    public List<TreeMap<Date, Double>> getChargeCurve() {
        return chargeCurve;
    }

    public void setChargeCurve(List<TreeMap<Date, Double>> chargeCurve) {
        this.chargeCurve = chargeCurve;
    }

    public List<TreeMap<Date, Double>> getDisChargeCurve() {
        return disChargeCurve;
    }

    public void setDisChargeCurve(List<TreeMap<Date, Double>> disChargeCurve) {
        this.disChargeCurve = disChargeCurve;
    }

    public List<TreeMap<Date, Double>> getUnkwonMeasMaps() {
        return unkwonMeasMaps;
    }

    public void setUnkwonMeasMaps(List<TreeMap<Date, Double>> unkwonMeasMaps) {
        this.unkwonMeasMaps = unkwonMeasMaps;
    }


    public Double getChargeIntegral() {
        return chargeIntegral;
    }

    public Double getDischargeIntegral() {
        return dischargeIntegral;
    }

    public Double getUnkownIntegral() {
        return unkownIntegral;
    }
    public void setChargeIntegral(Double chargeIntegral) {
        this.chargeIntegral = chargeIntegral;
    }

    public void setDischargeIntegral(Double dischargeIntegral) {
        this.dischargeIntegral = dischargeIntegral;
    }

    public void setUnkownIntegral(Double unkownIntegral) {
        this.unkownIntegral = unkownIntegral;
    }

    public void calculatingPoints() {
        if (this.dischargeIntegral != null) {
            double v = calculateMultiIntegral(this.getDisChargeCurve());
            this.dischargeIntegral = v;
        }
        if (this.chargeIntegral != null) {
            double v = calculateMultiIntegral(this.getChargeCurve());
            this.chargeIntegral = v;
        }
        if (this.unkownIntegral != null) {
            ChargeAndDisChargeIntegral integral = calculateUnknownIntegral(this.getUnkwonMeasMaps());
            if (integral.getChargeIntegral() != 0) {
                this.chargeIntegral += integral.getChargeIntegral();
            }
            if (integral.getDisChargeIntegral() != 0) {
                this.dischargeIntegral += integral.getDisChargeIntegral();
            }
        }
    }


    /**
     * 计算多个段的值曲线一分钟面积积分之和,返回值单位为千瓦时
     *
     * @param values
     * @return
     */
    private double calculateMultiIntegral(List<TreeMap<Date, Double>> values) {
        double integral = 0;
        for (TreeMap<Date, Double> value : values) {
            integral += getIntegralFromArrayByMin(value);
        }
        return integral;
    }


    /**
     * 计算给定正负方向的功率曲线得面积积分
     * 梯形
     * @param ar 充电 或者是 放电时的曲线积分
     * @return 一个计算曲线面积的积分
     */
    private double getIntegralFromArrayByMin(TreeMap<Date, Double>  ar) {
        BigDecimal integralSum = new BigDecimal(0);
        if (ar.size() < 2) {
            return integralSum.doubleValue();
        }
        Date[] dates = ar.keySet().toArray(new Date[]{});
        for (int i = 0; i < dates.length - 1; i++) {
            Date x1 = dates[i];
            Date x2 = dates[i+1];
            if(x2 == null || x1 == null) {
                continue;
            }
            Double y1 = ar.get(x1);
            Double y2 = ar.get(x2);
            BigDecimal result = calcTrapezoidIntegral(y1, y2, x1.toInstant().getEpochSecond(), x2.toInstant().getEpochSecond());
            // 将积分的结果由秒转化为小时
            integralSum = integralSum.add(result);
        }
        return integralSum.doubleValue();
    }




    /**
     * 矩形积分计算
     *
     * @param x1d
     * @param x2d
     * @param startSecond
     * @param endSecond
     * @return
     */
    public BigDecimal calcTrapezoidIntegral(double x1d, double x2d, long startSecond, long endSecond) {
        BigDecimal y1 = new BigDecimal(x1d);
        BigDecimal y2 = new BigDecimal(x2d);
        BigDecimal result = null;
        if (y1.compareTo(BigDecimal.ZERO) >= 0 && y2.compareTo(BigDecimal.ZERO) >= 0) {
            result = y1.add(y2).divide(new BigDecimal(2), 10, RoundingMode.DOWN);
        } else if (y1.compareTo(BigDecimal.ZERO) <= 0 && y2.compareTo(BigDecimal.ZERO) <= 0) {
            y1 = y1.abs();
            y2 = y2.abs();
            result = y1.add(y2).divide(new BigDecimal(2), 10, RoundingMode.DOWN);
        } else  {
            result = y1.abs();
        }
        Double high = Math.abs(3600d /  (startSecond - endSecond));
        return result.divide(BigDecimal.valueOf(high),10,RoundingMode.DOWN);
    }


    /**
     * 特殊处理功率无法判断切换的情况的计算
     *
     * @param unkwonMeasMaps 未知
     * @return
     */
    private ChargeAndDisChargeIntegral calculateUnknownIntegral(List<TreeMap<Date, Double>> unkwonMeasMaps) {
        double charge = 0.0;
        double disCharge = 0.0;
        for (TreeMap<Date, Double> meas : unkwonMeasMaps) {
            LinkedList<Date> dates = Lists.newLinkedList(meas.keySet());
            while (CollectionUtil.isNotEmpty(dates)) {
                Date x1 = dates.pollFirst();
                Date x2 = dates.pollFirst();
                Double x1v = meas.get(x1);
                Double x2v = meas.get(x2);
                if (x1v < 0) {
                    BigDecimal v = calcTrapezoidIntegral(x1v,x2v, x1.toInstant().getEpochSecond(), x2.toInstant().getEpochSecond()).abs();
                    if (v.doubleValue() != 0) {
                        charge += v.doubleValue();
                    }
                }
                if (x1v > 0) {
                    BigDecimal v = calcTrapezoidIntegral(x1v,x2v,x1.toInstant().getEpochSecond(),x2.toInstant().getEpochSecond()).abs();
                    if (v.doubleValue() != 0) {
                        disCharge += v.doubleValue();
                    }
                }
            }
        }
        return new ChargeAndDisChargeIntegral(charge, disCharge);
    }
}
